﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using AspNet.Identity.MongoDB;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using SignatureWebApi.Models;
using System.Web.Mvc;
using Microsoft.Owin.Security.Infrastructure;
#pragma warning disable 1591

namespace SignatureWebApi.Providers
{
    public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
    {
        private readonly string _publicClientId;

        public ApplicationOAuthProvider(string publicClientId)
        {
            if (publicClientId == null)
            {
                throw new ArgumentNullException(nameof(publicClientId));
            }

            _publicClientId = publicClientId;
        }

        /// <summary>
        /// 颁发用户token
        /// </summary>
        /// <param name="context">用户名 密码</param>
        /// <returns>返回token详细信息</returns>
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var ttttttttttt = context.Request;
            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
            if (user == null)
            {
                context.SetError("invalid_grant", "用户名或密码不正确。");
                return;
            }

            //context.OwinContext.Set("UserName", context.UserName);
            ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
               OAuthDefaults.AuthenticationType);
            ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                CookieAuthenticationDefaults.AuthenticationType);
            var roles = await userManager.GetRolesAsync(user.Id);
            var clams = await userManager.GetClaimsAsync(user.Id);
            //foreach (var rolesName in roles)
            //{
            //    oAuthIdentity.AddClaim(new Claim(ClaimTypes.Role, rolesName));
            //}
            //oAuthIdentity.AddClaim(new Claim());
            Dictionary<string, string> data = new Dictionary<string, string>
            {
                { "userName", user.UserName},
                { "realName",user.RealName}
            };
            AuthenticationProperties properties = CreateProperties(data);
            
            oAuthIdentity.AddClaim(new Claim("host", context.Request.Host.ToString()));
            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
            context.Validated(ticket);
            context.Request.Context.Authentication.SignIn(cookiesIdentity);

        }

        public override  Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
        {
            var newId = new ClaimsIdentity(context.Ticket.Identity);
            newId.AddClaim(new Claim("newClaim", "refreshToken"));
            var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);
            context.Validated(newTicket);
            return Task.FromResult<object>(context);
            //base.GrantRefreshToken(context);
        }
        public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {
            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }
            return Task.FromResult<object>(null);
        }
        public override Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
        {
            // var userMsg = context.OwinContext.GetUserManager<ApplicationUserManager>();
            //if (true)
            //{
                
            //}
            return base.AuthorizeEndpoint(context);
        }

        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            // 资源所有者密码凭据未提供客户端 ID。
            //if (context.ClientId == null)
            //{
            //    context.Validated();
            //}

            //return Task.FromResult<object>(null);
           
            string clientId;
            string clientSecret;
            context.TryGetFormCredentials(out clientId, out clientSecret);
            if (clientId == _publicClientId && clientSecret == "WebApi")
            {
                context.Validated(clientId);
            }
            else
            {
                //context.Response.StatusCode = Convert.ToInt32(HttpStatusCode.OK);
                context.SetError("invalid_client", "client is not valid");
            }
            return base.ValidateClientAuthentication(context);
            // return Task.FromResult<object>(context);
        }
        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            /*
                 var client = _oauthClientService.GetClient(context.ClientId);
                 oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName));
             */
            var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
            oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.ClientId));
            //oAuthIdentity.AddClaim(new Claim(ClaimTypes.Role, "ClientType")); 
            var propsDictionary = new Dictionary<string, string> { { "client_id", context.ClientId } };
            var props = new AuthenticationProperties(propsDictionary) { AllowRefresh = true };
            var ticket = new AuthenticationTicket(oAuthIdentity, props);
            context.Validated(ticket);
            return Task.FromResult<object>(context);
            //return base.GrantClientCredentials(context);
        }
        public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            if (context.ClientId == _publicClientId)
            {
                Uri expectedRootUri = new Uri(context.Request.Uri, "/");

                if (expectedRootUri.AbsoluteUri == context.RedirectUri)
                {
                    context.Validated();
                }
            }

            return Task.FromResult<object>(null);
        }

        

        public static AuthenticationProperties CreateProperties(string userName)
        {
            IDictionary<string, string> data = new Dictionary<string, string>
            {
                { "userName", userName }
            };
            return new AuthenticationProperties(data);
        }
        public static AuthenticationProperties CreateProperties(Dictionary<string, string> prop)
        {
            
            return new AuthenticationProperties(prop);
        }
    }

    public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider
    {
        public override Task CreateAsync(AuthenticationTokenCreateContext context)
        {   
            //string tokenValue = Guid.NewGuid().ToString("n");
            context.Ticket.Properties.IssuedUtc = DateTime.UtcNow;
            context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddDays(5);
            context.Ticket.Properties.AllowRefresh = true;
            context.SetToken(context.SerializeTicket());
            //var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
            //var userName = context.OwinContext.Get<string>("UserName");
            return Task.FromResult<object>(context);
        }



        public override Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            context.DeserializeTicket(context.Token);
            //var ttt = context.Ticket.Properties;
            //var tttt = context.Ticket.Identity;
            return Task.FromResult<object>(context);
        }
    }
    //public class ApplicationAccessTokenProvider : AuthenticationTokenProvider
    //{
        
    //    public override Task ReceiveAsync(AuthenticationTokenReceiveContext context)
    //    {
    //        context.DeserializeTicket(context.Token);
    //        var ttt = context.Ticket.Properties;
    //        var tttt = context.Ticket.Identity;
    //        return Task.FromResult<object>(context);
    //    }
    //}

}